CRANE_NS_BEGIN
namespace net {

StringView URL_parse_scheme(std::string_view str)
{
    auto pos = str.find_first_of(':');
    if ( pos == std::string_view::npos ) return std::string_view{};
    if ( pos == 0 || pos + 3 >= str.length() ) return std::string_view{};
    if ( str[pos + 1] != '/' || str[pos + 2] != '/' ) return std::string_view{};

    return str.substr(0, pos);
}

StringView URL_parse_authority(std::string_view str)
{
    auto pos = str.find_first_of("/?#"); 
    if ( pos != std::string_view::npos ) return str.substr(0, pos);
    else return str;
}

StringView URL_parse_path(std::string_view str)
{
    auto pos = str.find_first_of("?#"); 
    if ( pos == std::string_view::npos ) return std::string_view{};

    return str.substr(0, pos);
}

StringView URL_parse_query(std::string_view str)
{
    auto pos = str.find_first_of("#"); 
    if ( pos == std::string_view::npos ) return std::string_view{};

    return str.substr(pos);
}

void URL_parse(Url & url, std::string_view str)
{
    std::string_view str0 = URL_parse_scheme(str);

    url.m_scheme = URL_parse_scheme(str0);
    str0 = std::string_view(str0.data() + url.m_scheme.length() + 3, str0.length() - url.m_scheme.length() - 3);
    if (str0.empty()) return ;

    url.m_authority = URL_parse_authority(str0);
    str0 = std::string_view(str0.data() + url.m_authority.length(), str0.length() - url.m_authority.length());
    if (str0.empty()) return ;

    if (str[0] == '/') {
        url.m_path = URL_parse_path(str0);
        str0 = std::string_view(str0.data() + url.m_path.length(), str0.length() - url.m_path.length());
        if (str0.empty()) return ;
    }

    if ( str0[0] == '?') {
        url.m_query = URL_parse_query(str0);
        str0 = std::string_view(str0.data() + url.m_query.length(), str0.length() - url.m_query.length());
        if (str0.empty()) return ;
    }

    if (str0[0] == '#') url.m_fragment = str0.substr(1);
}

CRANE_INLINE
Url::Url(const Url &other)
    : m_url(other.m_url)
    , m_scheme(m_url.data() + (other.m_scheme.data() - other.m_url.data()), other.m_scheme.length())
    , m_authority(m_url.data() + (other.m_authority.data() - other.m_url.data()), other.m_authority.length())
    , m_user(m_url.data() + (other.m_user.data() - other.m_url.data()), other.m_user.length())
    , m_pass(m_url.data() + (other.m_pass.data() - other.m_url.data()), other.m_pass.length())
    , m_host(m_url.data() + (other.m_host.data() - other.m_url.data()), other.m_host.length())
    , m_port(m_url.data() + (other.m_port.data() - other.m_url.data()), other.m_port.length())
    , m_path(m_url.data() + (other.m_path.data() - other.m_url.data()), other.m_path.length())
    , m_query(m_url.data() + (other.m_query.data() - other.m_url.data()), other.m_query.length())
    , m_fragment(m_url.data() + (other.m_fragment.data() - other.m_url.data()), other.m_fragment.length())
{}

CRANE_INLINE
Url& Url::operator=(const Url &other) {
    if ( this == &other ) return *this;
    m_url = other.m_url;
    if ( !other.m_scheme.empty() ) {
        m_scheme = StringView(m_url.data() + (other.m_scheme.data() - other.m_url.data()), other.m_scheme.length()); 
    }
    if ( !other.m_authority.empty() ) {
        m_authority = StringView(m_url.data() + (other.m_authority.data() - other.m_url.data()), other.m_authority.length());
    }
    if ( !other.m_user.empty() ) {
        m_user = StringView(m_url.data() + (other.m_user.data() - other.m_url.data()), other.m_user.length());
    }
    if ( !other.m_pass.empty() ) {
        m_pass = StringView(m_url.data() + (other.m_pass.data() - other.m_url.data()), other.m_pass.length());
    }
    if ( !other.m_host.empty() ) {
        m_host = StringView(m_url.data() + (other.m_host.data() - other.m_url.data()), other.m_host.length());
    }
    if ( !other.m_port.empty() ) {
        m_port = StringView(m_url.data() + (other.m_port.data() - other.m_url.data()), other.m_port.length());
    }
    if ( !other.m_path.empty() ) {
        m_path = StringView(m_url.data() + (other.m_path.data() - other.m_url.data()), other.m_path.length());
    }
    if ( !other.m_query.empty() ) {
        m_query = StringView(m_url.data() + (other.m_query.data() - other.m_url.data()), other.m_query.length());
    }
    if ( !other.m_fragment.empty() ) {
        m_fragment = StringView(m_url.data() + (other.m_fragment.data() - other.m_url.data()), other.m_fragment.length());
    }

    return *this;
}

} // net
CRANE_NS_END
